package com.quectel.core.module.forum.service.impl.mongo;

import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.forum.ForumConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.util.aspect.lock.annotation.Lock;
import com.quectel.core.constants.MongoCollectionConstants;
import com.quectel.core.constants.RedisLockConstants;
import com.quectel.core.module.MongoAuthComponent;
import com.quectel.core.module.forum.dto.ForumTopicDto;
import com.quectel.core.module.forum.dto.mongo.ForumTopicCountDto;
import com.quectel.core.module.forum.entity.mongo.ForumTopicCountModel;
import com.quectel.core.module.forum.service.ForumTopicService;
import com.quectel.core.module.forum.service.mongo.ForumTopicCountService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.Request;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mongo.MongodbUtils;
import com.quectel.util.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/5/8 15:52
 * @description 帖子
 */
@DubboService
@Slf4j
public class ForumTopicCountServiceImpl implements ForumTopicCountService {
    @Autowired
    private MongoAuthComponent mongoAuthComponent;
    @Autowired
    private ForumTopicService forumTopicService;

    private Criteria sqlWhere(Map<String, Object> params) {
        Request request = Request.configParams(params);

        Criteria criteria = new Criteria();
        Long id = request.getLong(LambdaUtil.getFieldName(ForumTopicCountDto::getId));
        if (id != null) {
            criteria.andOperator(Criteria.where(SystemConstants.MONGO_ENTITY_ID_FLAG).is(id));
        }

        Long topicId = request.getLong(LambdaUtil.getFieldName(ForumTopicCountDto::getTopicId));
        if (topicId != null) {
            criteria.andOperator(Criteria.where(LambdaUtil.getFieldName(ForumTopicCountDto::getTopicId)).is(topicId));
        }
        Object[] array = request.getArray(ForumConstants.TOPICS, Object.class);
        if (array != null && array.length > 0) {
            criteria.andOperator(Criteria.where(LambdaUtil.getFieldName(ForumTopicCountDto::getTopicId)).in(array));
        }

        return new Criteria().andOperator(criteria);
    }

    @Override
    @Lock(
            lockExpresses = {
                    RedisLockConstants.FORUM_TOPIC_LOCK + "#{#topicId}"
            }
    )
    public void updateTopicCount(Long topicId, Byte handleType, Integer offset) {
        ForumTopicCountDto dbDto = selectByTopicId(topicId);
        if (dbDto == null) {
            dbDto = new ForumTopicCountDto();
            dbDto.setTopicId(topicId);
            dbDto.setId(save(dbDto));
        }

        ForumConstants.ForumHandleType byType = ForumConstants.ForumHandleType.getByType(handleType);
        if (byType == null) {
            return;
        }

        Integer count = 0;
        try {
            Field field = ReflectionUtils.findField(ForumTopicCountDto.class, byType.getFieldName() + "Count");
            if (field != null) {
                field.setAccessible(true);
                count = (Integer) field.get(dbDto);
                count += offset;
                ReflectionUtils.setField(field, dbDto, count <= 0 ? 0 : count);
                ForumTopicCountService forumTopicCountService = SpringUtils.getBean(ForumTopicCountService.class);
                //更新操作
                forumTopicCountService.updateById(dbDto);
            }

        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }

    }

    @Override
    public ForumTopicCountDto selectById(Long id) {
        ForumTopicCountModel one = MongodbUtils.findOne(id, MongoCollectionConstants.FORUM_TOPIC_COUNT, ForumTopicCountModel.class);
        return CopyUtils.copyObj(one, ForumTopicCountDto.class);
    }

    @Override
    public ForumTopicCountDto selectByTopicId(Long topicId) {
        Query query = new Query();
        query.addCriteria(Criteria.where(LambdaUtil.getFieldName(ForumTopicCountModel::getTopicId)).is(topicId));

        ForumTopicCountModel one = MongodbUtils.findOneData(ForumTopicCountModel.class, query, MongoCollectionConstants.FORUM_TOPIC_COUNT);
        return CopyUtils.copyObj(one, ForumTopicCountDto.class);
    }

    @Override
    public void updateById(ForumTopicCountDto dto) {
        ForumTopicCountModel entity = CopyUtils.copyObj(dto, ForumTopicCountModel.class);
        MongodbUtils.update(
                entity,
                new Update()
                        .set(LambdaUtil.getFieldName(ForumTopicCountDto::getTopicId), entity.getTopicId())
                        .set(LambdaUtil.getFieldName(ForumTopicCountDto::getPostCount), entity.getPostCount())
                        .set(LambdaUtil.getFieldName(ForumTopicCountDto::getCommentCount), entity.getCommentCount())
                        .set(LambdaUtil.getFieldName(ForumTopicCountDto::getLikeCount), entity.getLikeCount())
                        .set(LambdaUtil.getFieldName(ForumTopicCountDto::getShareCount), entity.getShareCount()),
                MongoCollectionConstants.FORUM_TOPIC_COUNT

        );
    }

    @Override
    public List<ForumTopicCountDto> queryList(Map<String, Object> params) {
        Request request = Request.configParams(params);

        return
                MongodbUtils.page(
                        new Query(sqlWhere(params)),
                        request.getPageNo() - 1,
                        request.getPageSize(),
                        Sort.by(Sort.Order.desc(LambdaUtil.getFieldName(ForumTopicCountModel::getPostCount)), Sort.Order.desc(SystemConstants.ENTITY_ID_FLAG)),
                        ForumTopicCountModel.class,
                        MongoCollectionConstants.FORUM_TOPIC_COUNT
                ).stream().map(model -> {
                    ForumTopicCountDto dto = CopyUtils.copyObj(model, ForumTopicCountDto.class);
                    if (dto != null) {
                        ForumTopicDto forumTopicDto = forumTopicService.selectCacheById(dto.getTopicId());
                        if (forumTopicDto != null) {
                            dto.setTopicName(forumTopicDto.getName());
                        }
                    }
                    return dto;
                }).collect(Collectors.toList());
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return (int) MongodbUtils.count(new Query(sqlWhere(params)), MongoCollectionConstants.FORUM_TOPIC_COUNT);
    }

    @Override
    public Long save(ForumTopicCountDto dto) {
        ForumTopicCountModel entity = CopyUtils.copyObj(dto, ForumTopicCountModel.class);
        entity.setId(Snowflake.nextId());
        MongodbUtils.insert(entity, MongoCollectionConstants.FORUM_TOPIC_COUNT);
        return entity.getId();
    }


    @Override
    public void deleteById(Long id) {
        MongodbUtils.delete(id, MongoCollectionConstants.FORUM_TOPIC_COUNT);
    }

    @Override
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            MongodbUtils.delete(id, MongoCollectionConstants.FORUM_TOPIC_COUNT);
        }
    }
}
